﻿using Collector.Device.Notify;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Collector.Device
{
    class GenericMold
    {
        private string TAG = "GenericMold:";
        private AutoResetEvent conditionWait = new AutoResetEvent(false);
        public static readonly int THREE_BODY_PART_SNR_MAXIMUM = 3;
        private PulseGeneralCollector mGeneralCollector = new PulseGeneralCollector();
        private DeviceCommunicationManager mDCManager = new DeviceCommunicationManager();
        private PulseApplicantion mApplication = new PulseApplicantion();
        private SerialPortImpl mSerialPort = new SerialPortImpl();

        private string mMCUTargetVersion;
        private string mDeviceSerialNumber;
        // mBar
        private double[] mBaselines = new double[3];
        private double mFixedFrequency;
        private bool isPrepared = false;
        private CollectorState mState = 0;
        // 配置定时器
        System.Timers.Timer mSensorTimer = new System.Timers.Timer(100);
        System.Timers.Timer mTestTimer = new System.Timers.Timer(1000);
        private int mTimeCount = 0;

        public event FormNotifyDelegate<PulseCommonHelper.Display> notifyForm;

        public AutoResetEvent ConditionWait
        {
            get { return conditionWait; }
        }

        public double[] Baselines
        {
            get { return mBaselines; }
        }

        public string DeviceSerialNumber
        {
            get { return mDeviceSerialNumber; }
        }

        public DeviceCommunicationManager DCManager 
        {
            get { return mDCManager; }
        }

        public SerialPortImpl SerialPort
        {
            get { return mSerialPort; }
        }

        public CollectorState State
        {
            set { mState = value; }
            get { return mState; }
        }

        protected bool initialization()
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            bool ret = false;

            if(notifyForm == null)
            {
                Log.Error(TAG + "FormNotifyDelegate is not set");
                return false;
            }

            if (mSerialPort.open(mDCManager.SerialPortReceivedCallback) == false)
            {
                display.Message = string.Format("comPort {0} Open Status:{1}", mSerialPort.PortName, false);
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                return false;
            }
            else
            {
                display.Message = string.Format("comPort {0} Open Status:{1}", mSerialPort.PortName, true);
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                CollectorIntention intention = new CollectorIntention("测试串口 :" + mSerialPort.PortName, CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_SERIALPORT_LABLE);
                display.UserData = intention;
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);
            }

            // Initialize params 
            // Default set general collector.
            mSerialPort.SerialPort.collector = mGeneralCollector;
            mGeneralCollector.DeviceAdapter = mDCManager;
            // 重置 脉象协议处理类配置
            mDCManager.ResetConfig();
            mDCManager.DeviceConnector = mSerialPort.SerialPort;
            // 用于接收实时脉压和气压值
            mDCManager.DeliveredCallback = DeliveredPulsePressureDataCallback;

            // 打开脉象设备灯，保持长亮
            mDCManager.OpenDeviceLed();

            // 请求复位设备
            mDCManager.ResetDevice();

            mTimeCount = 0;
            timerCreateTotalTest(mTestTimer);
            //开始定时器，100ms频次显示当前脉压值和脉压差值
            timerSensorSetting(mSensorTimer);

            checkDeviceVersion();

            conditionWait.Set();
            return true;
        }

        protected void deinitialization()
        {
            resetDeviceStatus();
            conditionWait.WaitOne();
            mSerialPort.close(mDCManager.SerialPortReceivedCallback);
            if(mDCManager.DeviceConnector != null)
            {
                mDCManager.DeviceConnector = null;
            }
            
            timerSensorDesetting(mSensorTimer);
            timerDeleteTotalTest(mTestTimer);
        }

        protected bool checkDeviceVersion()
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            bool ret = false;
            /**
             * 版本号检查
             */
            string MCUConfigVersion;
            // 从配置文件中读取设备的测试目标版本号
            FileConfig.getmmHgListInfo("CheckMcuVersion", out MCUConfigVersion);
            // 从设备读取固件版本号            
            ret = mDCManager.ReadMcuVersion(out mMCUTargetVersion);
            if (!ret)
            {
                display.Message = "Read Mcu Version err";
            }
            else
            {
                CollectorIntention intent = new CollectorIntention();
                ret = MCUConfigVersion.Trim() == mMCUTargetVersion.Trim();
                intent.Message = mMCUTargetVersion;
                intent.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_DEVICE_VERSION;
                intent.Result = ret;
                display.LogLevel = (ret) ? LogMsgType.INFO : LogMsgType.ERROR;
                display.UserData = intent;
                // notify mcu version check result
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);

                // nitify mcu ui info
                display.Message = string.Format("Read:{0},config:{1}", mMCUTargetVersion, MCUConfigVersion);                
            }

            display.LogLevel = (ret) ? LogMsgType.INFO : LogMsgType.ERROR;
            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);        

            return ret;
        }

        protected bool checkAndPreparedDeviceInfo()
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            bool ret = false;

            /**
             * 读取设备SN
             */

            if (!(ret = mDCManager.ReadSerialNumber(out mDeviceSerialNumber)))
            {
                display.Message = "Read MCU SerialNumber Fail";
            }
            else
            {
                display.Message = "Get SN :" + mDeviceSerialNumber;
            }

            display.LogLevel = (ret) ? LogMsgType.INFO : LogMsgType.ERROR;
            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);

            if (!ret) return ret;

            /**
             * 读取基线压力
             */
            ret = mDCManager.ReadInitialPPressure(ref mBaselines);
            if (!ret)
            {
                display.Message = "读取初始静压失败";
                display.LogLevel = (ret) ? LogMsgType.INFO : LogMsgType.ERROR;
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                return ret;
            }
            else
            {
                for (int i = 0; i < THREE_BODY_PART_SNR_MAXIMUM; i++)
                {
                    Log.Debug(TAG + "Get baseline[{0}]: {1}", i, mBaselines[i]);
                    if (mBaselines[i] > (FileConfig.GetThresholdValue("BaseLine_UPZH") / 32.0) ||
                        mBaselines[i] < (FileConfig.GetThresholdValue("BaseLine_LowZH") / 32.0))
                    {
                        Log.Error(TAG + string.Format("初始静压值不正确:{0}", mBaselines[i]));
                        display.Message = "读取初始静压失败";
                        display.LogLevel = LogMsgType.ERROR;
                        notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                        return false;
                    }

                    if (!FileConfig.PulseThreeBodyTest())
                    {
                        break;
                    }
                }

                CollectorIntention intent = new CollectorIntention();
                intent.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_BASELINE;
                intent.Data = mBaselines;
                display.UserData = intent;
                display.LogLevel = (ret) ? LogMsgType.INFO : LogMsgType.ERROR;
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);
            }

            // 读取气泵固定频率
            string fixedFreqValue;
            if (mDCManager.ReadDeviceFixedFre(out fixedFreqValue))
            {
                double mFixedFrequency = Math.Round((Convert.ToDouble(fixedFreqValue.Substring(0, 4)) / 100), 2);
                Log.Debug(TAG + string.Format("Get fixedFrequency :{0}", mFixedFrequency));
            }

            /**
             * 开启脉压和气压采集
             */
            byte[] temp;
            ret = mDCManager.SendCommandToDevice("SPStartPulsePressure", 0x64, out temp);
            if (!ret)
            {
                string msg = "开启脉压收集失败";
                Log.Error(TAG + msg);
                display.Message = msg;
                display.LogLevel = LogMsgType.ERROR;
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                return ret;
            }

            ret = mDCManager.SendCommandToDevice("SPStartAirPressure", 0x95, out temp);
            if (!ret)
            {
                string msg = "开启气压收集失败";
                Log.Error(TAG + msg);
                display.Message = msg;
                display.LogLevel = LogMsgType.ERROR;
                notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_MSG);
                return ret;
            }

            isPrepared = true;
            return ret;
        }

        protected bool resetDeviceStatus()
        {
            byte[] payload;
            if (null == mSerialPort.SerialPort)
            {
                Log.Warn(TAG + "resetDeviceStatus() Pulse Serialport is released");
                return false;
            }

            if (!mDCManager.SendCommandToDevice("SPStopPulsePressure", 0x74, out payload))
            {
                Log.Error(TAG + "resetDeviceStatus() Stop pulse pressure collect failed");
                return false;
            }

            if (!mDCManager.SendCommandToDevice("SPStopAirPressure", 0x96, out payload))
            {
                Log.Error(TAG + "resetDeviceStatus() Stop air pressure collect failed");
                return false;
            }

            if (!mDCManager.ResetDevice())
            {
                Log.Error(TAG + "resetDeviceStatus() Reset device status failed");
                return false;
            }
            else
            {
                Log.Info(TAG + "resetDeviceStatus() Reset device status Successfuly");
            }

            return true;
        }

        protected bool writeDeviceSerialnumber(string newSn, out string reason)
        {
            return mDCManager.WriteSerialNumber(newSn, out reason);
        }

        virtual protected bool readDeviceSerialnumber(out string serialnumber)
        {
            return mDCManager.ReadSerialNumber(out serialnumber);
        }

        private void timerCreateTotalTest(System.Timers.Timer t)
        {
            t.Elapsed += new System.Timers.ElapsedEventHandler(updateTestTotalTime);
            t.AutoReset = true;
            t.Enabled = true;
            t.Start();
        }

        private void timerDeleteTotalTest(System.Timers.Timer t)
        {
            t.Elapsed -= new System.Timers.ElapsedEventHandler(updateTestTotalTime);
            t.AutoReset = false;
            t.Enabled = false;
            t.Stop();
        }

        private void updateTestTotalTime(Object myObject, EventArgs myEventArgs)
        {
            mTimeCount++;
            TimeSpan temp = new TimeSpan(0, 0, mTimeCount);

            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            string message = string.Format("{0}{1:00}:{2:00}:{3:00}", "测试时长 :", temp.Hours, temp.Minutes, temp.Seconds);
            CollectorIntention intention = new CollectorIntention(message, CollectorIntention.IntentionType.eINTENT_TYPE_REFRESH_TEST_TIME);
            display.UserData = intention;
            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);


        }

        private void timerSensorSetting(System.Timers.Timer t)
        {
            t.Interval = 100;
            t.Elapsed += new System.Timers.ElapsedEventHandler(getGraphCurveValue);
            t.AutoReset = true;
            t.Enabled = true;
            t.Start();
        }

        private void timerSensorDesetting(System.Timers.Timer t)
        {
            if (t.Enabled)
            {
                t.Elapsed -= new System.Timers.ElapsedEventHandler(getGraphCurveValue);
                t.AutoReset = false;
                t.Enabled = false;
                t.Stop();
            }
        }
        
        private bool DeliveredPulsePressureDataCallback(byte[] frame, double data, PulseProtocolPackage.PressureType type)
        {
            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            if (mState == CollectorState.eCOLLECTOR_STATE_COMPLETED)
                return true;

            switch (type)
            {
                case PulseProtocolPackage.PressureType.ePRESSURE_TYPE_PULSE:
                    {
                        if (FileConfig.PulseThreeBodyTest())
                        {
                            mApplication.pushPulseData(frame, ProductType.ePRODUCT_TYPE_THREE);

                            // Update scope plotlab value
                            var pluseDataMap = mApplication.PluseData;

                            CollectorIntention intention = new CollectorIntention();
                            intention.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_SENSOR_DATA;
                            intention.PressureType = PulseProtocolPackage.PressureType.ePRESSURE_TYPE_PULSE;
                            foreach (var it in PulseApplicantion.TBPIndexMap)
                            {
                                intention.AverageData[it.Key] = Math.Round(pluseDataMap[it.Value].Last(), 2);
                            }
                            display.UserData = intention;
                            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);
                        }
                        else
                        {
                            mApplication.pushPulseData(frame, ProductType.ePRODUCT_TYPE_SINGLE);
                            // Update scope plotlab value
                            var pluseDataMap = mApplication.PluseData;

                            CollectorIntention intention = new CollectorIntention();
                            intention.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_SENSOR_DATA;
                            intention.PressureType = PulseProtocolPackage.PressureType.ePRESSURE_TYPE_PULSE;
                            intention.AverageData[0] = Math.Round(pluseDataMap[BodyPart.eBODY_PART_CUN].Last(), 2);
                            display.UserData = intention;
                            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);

                        }
                    }
                    break;
                case PulseProtocolPackage.PressureType.ePRESSURE_TYPE_AIR:
                    {
                        CollectorIntention intention = new CollectorIntention();
                        intention.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_SENSOR_DATA;
                        intention.PressureType = PulseProtocolPackage.PressureType.ePRESSURE_TYPE_AIR;
                        intention.Data = (object)data;
                        display.UserData = intention;
                        notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);

                    }
                    break;
            }

            return true;
        }

        private void getGraphCurveValue(Object myObject, EventArgs myEventArgs)
        {

            PulseCommonHelper.Display display = new PulseCommonHelper.Display();
            CollectorIntention intention = new CollectorIntention();
            intention.Type = CollectorIntention.IntentionType.eINTENT_TYPE_UPDATE_GRAPH_CURVE;
            if (FileConfig.PulseThreeBodyTest())
            {
                foreach (var it in PulseApplicantion.TBPIndexMap)
                {
                    double ave = mApplication.PluseData[it.Value].Average();
                    intention.AverageData[it.Key] = ave;
                }
            }
            else
            {
                intention.AverageData[0] = Math.Round(mApplication.PluseData[BodyPart.eBODY_PART_CUN].Average(), 2);
            }

            display.UserData = intention;
            notifyMessage(display, PulseCommonHelper.Display.DisplayType.eDISPLAY_TYPE_USER);

        }

        public void notifyMessage(PulseCommonHelper.Display display, PulseCommonHelper.Display.DisplayType type)
        {
            notifyForm?.Invoke(display, type);            
        }
    }
}
